package com.whcoding.jwt.token.interceptor;


import com.alibaba.fastjson.JSON;
import com.whcoding.jwt.token.annotation.TokenAuthentication;
import com.whcoding.jwt.token.constant.AuthLevelEnum;
import com.whcoding.jwt.token.constant.JwtAuthorizedConstant;
import com.whcoding.jwt.token.entity.TokenResultVO;
import com.whcoding.jwt.token.service.UserService;
import com.whcoding.jwt.token.util.AnnotatioUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 自定义Token验证拦截器
 */
@Component
public class JwtInterceptor implements HandlerInterceptor {

	@Autowired
	UserService userService;

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

		//1.获取请求的url
		String url = request.getRequestURI();
		//2.从http 请求头中取出 token
		String token = request.getHeader("Authorization");
		//3.如果请求不是映射到方法直接通过
		if (!(handler instanceof HandlerMethod)) {
			return true;
		}

		//4.当前请求方法、请求类
		Method reqMethod = ((HandlerMethod) handler).getMethod();
		Class reqClass = reqMethod.getDeclaringClass();

		//5.获取当前请求方法上的授权验证注解，并验证授权级别是否为开放级别，若是开放，则直接返回，不在继续验证
		AuthLevelEnum authLevel = getReqAuthLevel(handler);
		if (authLevel == AuthLevelEnum.NO_AUTH) {
			return true;
		}

		//6.Token有效性验证
		if (!this.exeTokenAuthorized(request, response)) {
			return false;
		}

		// 不做身份权限验证
		if (authLevel == AuthLevelEnum.COMMON_API) {
			return true;
		}
		// 验证权限，true 请求放行，false 请求拦截
		return this.exeCheckPrivilege(request, response);
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

	}


	/**
	 * 获取调用方法权限控制等级
	 */
	private AuthLevelEnum getReqAuthLevel(Object handler) {

		// 优先获取当前请求方法上的授权验证注解
		Method reqMethod = ((HandlerMethod) handler).getMethod();
		TokenAuthentication authMethod = (TokenAuthentication) AnnotatioUtil.getMethodAnnotation(reqMethod, TokenAuthentication.class);
		if (authMethod != null) {
			return authMethod.authLevel();
		}

		// 获取当前请求类上的授权验证注解
		Class reqClass = reqMethod.getDeclaringClass();
		TokenAuthentication authClass = (TokenAuthentication) AnnotatioUtil.getClassAnnotation(reqClass, TokenAuthentication.class);
		if (authClass != null) {
			return authClass.authLevel();
		}

		// 默认需要权限控制
		return AuthLevelEnum.LOGIN;
	}


	/**
	 * 执行Token有效性验证
	 *
	 * @param request  请求
	 * @param response 响应
	 * @return true 请求放行  false 请求拦截
	 */
	private boolean exeTokenAuthorized(HttpServletRequest request, HttpServletResponse response) {
		// 获取token
		String token = request.getHeader("Authorization");

		//  这边拿到的 用户名 应该去数据库查询获得密码，简略，步骤在service直接获取密码
		//  boolean result = JwtUtil.verify(token, username, userService.getPassword());
		// todo （从redis中取）
		boolean result = true;
		if (!result) {
			this.buildErrorResponse(response, "token有误请检查！", null);
		}
		return true;
	}


	/**
	 * 执行权限验证
	 *
	 * @param request  请求
	 * @param response 响应
	 * @return true 请求放行  false 请求拦截
	 */
	private boolean exeCheckPrivilege(HttpServletRequest request, HttpServletResponse response) {
		// 获取token
		String token = request.getHeader("Authorization");

		String redisKey = "";//redisUtil.get(token).get("auth");

		if (Objects.isNull(redisKey)) {
			this.buildErrorResponse(response, "当前用户已在别处登录，请重新登录!", JwtAuthorizedConstant.TOKEN_EXPIRED_RESPONSE_STATUS);
			return false;
		}
		//redisUtil.get(token).get("auth");
		try {
			List<Map<String, Object>> auth = new ArrayList<>(16);
			if (auth == null || auth.size() < 1) {
				this.buildErrorResponse(response, "获取权限信息失败,请联系管理员分配相关权限！", null);
				return false;
			} else {

				List<String> list = new ArrayList<>();
				for (int i = 0; i < auth.size(); i++) {
					list.add(String.valueOf(auth.get(i).get("url")));
				}

				String url = request.getServletPath();
				String uri = url.substring(url.substring(url.indexOf("/") + 1).indexOf("/") + 2);

				if (uri.contains("?")) {
					uri = uri.substring(0, uri.indexOf("?"));
				}

				if (list.contains(uri)) {
					return true;
				} else {
					this.buildErrorResponse(response, "当前用户无相关操作权限!", null);
					return false;
				}
			}

		} catch (Exception e) {
			// 构建错误响应结果报文
			this.buildErrorResponse(response, "登录超时，请重新登录!", JwtAuthorizedConstant.TOKEN_EXPIRED_RESPONSE_STATUS);
			return false;
		}
	}


	/**
	 * 构建错误响应结果报文
	 *
	 * @param response 响应结果
	 * @param message  提示消息
	 */
	private void buildErrorResponse(HttpServletResponse response, String message, Integer status) {
		try {
			if (status == null) {
				// 定义响应状态，默认鉴权错误 缺少鉴权信息
				status = 203;
			}
			TokenResultVO tokenResultVO = new TokenResultVO();

			tokenResultVO.setCode(status);
			tokenResultVO.setMessage(message);

			// 设置响应结果
			response.setStatus(status);
			response.getWriter().append(JSON.toJSONString(tokenResultVO));

		} catch (IOException ioe) {
			System.out.println(ioe.getMessage());
		}
	}


}
